home *** CD-ROM | disk | FTP | other *** search
- unit CPUKind;
-
- interface
-
- uses
- SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
- Forms, Dialogs;
-
- type
- TCPUName = class(TComponent)
- private
- { Private declarations }
- function GetCPUKind: Integer;
- function GetCPUName: String;
- procedure NOPInteger (val: Integer);
- procedure NOPString (val: String);
- protected
- { Protected declarations }
- public
- { Public declarations }
- published
- { Published declarations }
- property CPUKind: Integer read GetCPUKind write NOPInteger; { read-only! }
- property CPUName: String read GetCPUName write NOPString; { read-only! }
- end;
-
- procedure Register;
-
- implementation
-
- const
- i8086 = 1; { includes 8088 CPU as well }
- i80286 = 2;
- i80386 = 3;
- i80486 = 4;
- iPentium = 5; { P5 - Pentium }
- iPentiumPro = 6; { P6 - Pentium Pro }
-
- var
- id: Integer;
-
- { Assembly function to get CPU type including Pentium and later }
-
- function CpuID: Integer; assembler;
- asm
- push ds { first, check for 8086 - Flag bits 12-15 always set }
- call GetWinFlags { call Windows API }
- or ax,wf_CPU286 { or with 80286 processor bit }
- mov ax,i80286 { assume 286 }
- jz @@1 { branch if it was }
-
- { Not a 80286 - let's check for a 8088/8086 next }
-
- pushf { save EFLAGS }
- pop bx { store EFLAGS in BX }
- mov ax,0fffh { clear bits 12-15 }
- and ax,bx { in EFLAGS }
- push ax { store new EFLAGS value on stack }
- popf { replace current EFLAGS value }
- pushf { set new EFLAGS }
- pop ax { store new EFLAGS in AX }
- and ax,0f000h { if bits 12-15 are set, then 8086 }
- cmp ax,0f000h { is an 8086/8088 ? }
- mov ax,i8086 { turn on 8086/8088 flag }
- je @@1 { yes - all done }
-
- { To test for 386 or better, we need to use 32 bit instructions,
- but the 16-bit Delphi assembler does not recognize the 32 bit opcodes
- or operands. Instead, use the 66H operand size prefix to change
- each instruction to its 32-bit equivalent. For 32-bit immediate
- operands, we also need to store the high word of the operand immediately
- following the instruction. The 32-bit instruction is shown in a comment
- after the 66H instruction.
- }
-
- db 66h { pushfd }
- pushf
- db 66h { pop eax }
- pop ax { get original EFLAGS }
- db 66h { mov ecx, eax }
- mov cx,ax { save original EFLAGS }
- db 66h { xor eax,40000h }
- xor ax,0h { flip AC bit in EFLAGS }
- dw 0004h
- db 66h { push eax }
- push ax { save for EFLAGS }
- db 66h { popfd }
- popf { copy to EFLAGS }
- db 66h { pushfd }
- pushf { push EFLAGS }
- db 66h { pop eax }
- pop ax { get new EFLAGS value }
- db 66h { xor eax,ecx }
- xor ax,cx { can't toggle AC bit, CPU=Intel386 }
- mov ax,i80386 { turn on 386 flag }
- je @@1
-
- { i486 DX CPU / i487 SX MCP and i486 SX CPU checking }
- { Checking for ability to set/clear ID flag (Bit 21) in EFLAGS }
- { which indicates the presence of a processor }
- { with the ability to use the CPUID instruction. }
-
- db 66h { pushfd }
- pushf { push original EFLAGS }
- db 66h { pop eax }
- pop ax { get original EFLAGS in eax }
- db 66h { mov ecx, eax }
- mov cx,ax { save original EFLAGS in ecx }
- db 66h { xor eax,200000h }
- xor ax,0h { flip ID bit in EFLAGS }
- dw 0020h
- db 66h { push eax }
- push ax { save for EFLAGS }
- db 66h { popfd }
- popf { copy to EFLAGS }
- db 66h { pushfd }
- pushf { push EFLAGS }
- db 66h { pop eax }
- pop ax { get new EFLAGS value }
- db 66h { xor eax, ecx }
- xor ax, cx
- mov ax,i80486 { turn on i486 flag }
- je @@1 { if ID bit cannot be changed, CPU=486 }
- { without CPUID instruction functionality }
-
- { Execute CPUID instruction to determine vendor, family, }
- { model and stepping. The use of the CPUID instruction used }
- { in this program can be used for B0 and later steppings }
- { of the P5 processor. }
-
- db 66h { mov eax, 1 }
- mov ax, 1 { set up for CPUID instruction }
- dw 0
- db 66h { cpuid }
- db 0Fh { Hardcoded opcode for CPUID instruction }
- db 0a2h
- db 66h { and eax, 0F00H }
- and ax, 0F00H { mask everything but family }
- dw 0
- db 66h { shr eax, 8 }
- shr ax, 8 { shift the cpu type down to the low byte }
- @@1:
- pop ds
- end;
-
- procedure TCPUName.NOPInteger(val: Integer); begin end;
- procedure TCPUName.NOPString(val: String); begin end;
-
- function TCPUName.GetCPUKind: Integer;
- begin
- Result := id;
- end;
-
- function TCPUName.GetCPUName: String;
- begin
- case id of
- i8086: Result := '8086';
- i80286: Result := '80286';
- i80386: Result := '80386';
- i80486: Result := '80486';
- iPentium: Result := 'Pentium';
- iPentiumPro: Result := 'Pentium Pro';
- else Result := Format ('P%d', [id]);
- end;
- end;
-
- procedure Register;
- begin
- RegisterComponents ('Pilgrim''s Progress', [TCPUName]);
- end;
-
- begin
- id := CpuID; { unit initialisation }
- end.
-